<?php 
	/**
	*  废话不多说，今天直接进入主题，PHP中的类与对象，现在都在搞面向对象，PHP也可以面向对
	*  象啊。什么是面向对象呢？那就是把世界上的事物共同属性和行为抽象出来，封装起来，做成一
	* 个公共的东西，用的时候调用就行，那遇到事物间的不通电了咋办？那就可以继承啊，不同点单
	*  独写出来就行了。面向对象的三大特性都快说完了：封装、继承、多态，慢慢研究吧。
	*/
	class Car {
		    public $name;
		    var $money;
		    function getName() {
		        	return $this->name;
		    }
		    function getMoney() {
		        	return $this->money;
		    }
	}

	//创建Car这个类的对象也就是实例化的时候用关键字 new来做
		
	$car = new Car();
	$car->name = '法拉利';
	$car->money = 100;
	echo $car->getName() . '价值' . $car->getMoney() . '万';
	echo "<br />";

	//也可以采用变量名来创建
	//也可以采用变量来创建
	$className = 'Car';
	$car = new $className();
	$car->name = '奥迪';
	$car->money = 200;
	echo $car->getName() . '价值' . $car->getMoney() . '万';
	echo "<br />";

	//刚才都说了，类嘛，有属性和行为组成，先来说说属性，属性声明是由关键字 public，protected 或者 private 开头，后面跟一个普通的变量声明来组成。属性的变量可以设置初始化的默认值，默认值必须是常量。访问控制的关键字代表的意义为：
		// public：公开的
		// protected：受保护的
		// private：私有的
	//默认都是public公有的，外部都可以访问，一般通过->对象操作符来访问对象的属性或者方法，对于静态属性则使用::双冒号进行访问。当在类成员方法内部调用的时候，可以使用$this伪变量调用当前对象的属性。

	class House {
		    //定义公共属性
		    public $name = '别墅';
		    //定义受保护的属性
		    protected $color = '白色';
		    //定义私有属性
		    private $price = '10000000';

		    private static $area = 100;

		    function __construct(){
			print '父类的构造函数被调用 <br />';
		    }

		    function __destruct(){
		    	print "父类的析构函数被调用 <br />";
		    }

		    public static function addArea(){
		    	self::$area += 50;
		    }

		    public static function getArea() {
		        return self::$area;
		    }
	}

	$house = new House();
	$house->name; //这个是可以访问的
	//$house->color; //这个就不行咯
	//$house->price; //这个也不行


	class BigHouse extends House {
		public function getColor() {
		        return $this->color; //内部访问受保护的属性
		}
		private $price = '100000';
		public function getPrice() {
		        return $this->price; //内部访问私有属性
		}
	}

	//这个BigHouse 是继承的House ，这里可以看出受保护的是自己和子类可以调用的，私有的只有自己可以调用，公共的谁都可以调用。
	$bigHouse = new BigHouse();
	echo $bigHouse->getPrice();
	echo "<br />";
	echo $bigHouse->getColor();
	echo "<br />";


	//说了属性该说方法了，其实就是function，面向过程的时候叫函数，面向对象就叫方法了，我类个擦。方法同样有访问控制，访问控制的关键字代表的意义为：
		// public：公开的
		// protected：受保护的
		// private：私有的
	//其实跟属性的访问控制是一样的，上面不都有例子嘛



	//构造函数和析构函数，PHP5以后可以在类中使用__construct()定义一个构造函数，具有构造函数的类，会在每次对象创建的时候调用该函数，因此常用来在对象创建的时候进行一些初始化工作。同样，PHP5以后也支持析构函数，使用__destruct()进行定义，析构函数指的是当某个对象的所有引用被删除，或者对象被显式的销毁时会执行的函数。

	class SmallHouse  extends House{
		function __construct(){
			//要不写下面的根本不会调用父类的构造函数
			parent::__construct();
			print '子类的构造函数被调用 <br />';
		}

		function __destruct(){
			//自动会调父类的析构函数，尼玛好像还不止一次，看来这个玩意不需要咱们自己写了
			print '子类的析构函数被调用 <br />';
		}
	}

	$smallHouse = new SmallHouse();



	//static 静态关键字，静态属性与方法可以在不实例化类的情况下调用，直接使用类名::方法名的方式进行调用。静态属性不允许对象使用->操作符调用。

	class MiddleHouse extends House{
		    private static $height = 100;
		    
		    public static function getHeight() {
		        return self::$height;
		    }

		    public static function areaAdd(){
		    	parent::addArea();
		    }
	}

	echo MiddleHouse::getHeight() . '<br />';
	// 静态方法也可以通过变量来进行动态调用的哦

	//来看看与父类的结合
	MiddleHouse::areaAdd();

	echo MiddleHouse::getArea() . "<br />";



	//上面我们了解到访问控制了，那在设计一个类的时候必须是要加上访问控制的（特别是属性），不加默认是公有的，但是不能这样哦。
	//如果构造函数定义成了私有方法，则不允许直接实例化对象了，这时候一般通过静态方法进行实例化，在设计模式中会经常使用这样的方法来控制对象的创建，比如单例模式只允许有一个全局唯一的对象。

	class Tea{
		private function __construct(){
			echo "这是茶！ <br />";
		}
		//这就是单例啊！！！
		 private static $_object = null;
	   	 public static function getInstance() {
		        if (empty(self::$_object)) {
		            self::$_object = new Tea(); 
		            //内部方法可以调用私有方法，因此这里可以创建对象
		        }
		        return self::$_object;
    		}
	}

	//那你也看到了，这是个单例，全局只能一个，不能 new 来实例化了，只能通过静态方式来获得一个实例。

	$tea = Tea::getInstance();


	//PHP中的重载指的是动态的创建属性与方法，是通过魔术方法来实现的。属性的重载通过__set，__get，__isset，__unset来分别实现对不存在属性的赋值、读取、判断属性是否设置、销毁属性。

	class Pen{
		private $array = array();

		public function __set($key, $value){
			$this->array[$key] = $value;
		}


		public function __get($key){
			if (isset($this->array[$key])) {
				return $this->array[$key];
			}
			return null;
		}

		public function __isset($key){
			if (isset($this->array[$key])) {
				return true;
			}
			return false;
		}

		public function __unset($key){
			unset($this->array[$key]);
		}
	}

	$pen = new Pen();	
	$pen -> length = 10;  //length属性动态创建并赋值
	echo $pen -> length;
	echo "<br />";


	//方法的重载通过__call来实现，当调用不存在的方法的时候，将会转为参数调用__call方法，当调用不存在的静态方法时会使用__callStatic重载。

	class Person{
		public $name = '人啊';

		public function __call($name, $args){
			if ($name == 'test') {
				$this->name = '重新赋值的人啊';
			}
		}
	}

	$person = new Person();

	$person ->test(); //调用了一个不存在的方法会使用重载

	echo $person->name . '<br />'; 


	//来一些高级特性
	//当同一个类的所有属性都相等时可以使用 == 和 ===（全等运算）来比较。


	$a = new Person();
	$b = new Person();

	if ($a == $b) {
		echo "== <br />";
	}elseif ($a === $b) {
		echo "=== <br />";
	}

	//对象复制，在一些特殊情况下，可以通过关键字clone来复制一个对象，这时__clone方法会被调用，通过这个魔术方法来设置属性的值。
	class Man {
		    public $name = '男人';
		    
		    public function __clone() {
			        $obj = new Man();
			        $obj->name = $this->name;
		    }
	}

	$a = new Man();
	$a->name = 'new  man';
	$b = clone $a;
	var_dump($b);
	echo "<br />";

	//对象序列化，可以通过serialize方法将对象序列化为字符串，用于存储或者传递数据，然后在需要的时候通过unserialize将字符串反序列化成对象进行使用。


	class Woman {
	    	public $name = '女人';
	}

	$a = new Woman();
	$str = serialize($a); //对象序列化成字符串
	echo $str.'<br>';
	$b = unserialize($str); //反序列化为对象
	var_dump($b);

	echo "<br />";



	
